/**
 * 
 */
package example;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.pi4.locutil.GeoPosition;
import org.pi4.locutil.MACAddress;
import org.pi4.locutil.Statistics;
import org.pi4.locutil.io.TraceGenerator;
import org.pi4.locutil.trace.Parser;
import org.pi4.locutil.trace.TraceEntry;

/**
 * @author Stenner
 *
 */
public class fingerprintingKNN {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		int k = 3;
		int n = 1;
		int offlineSize = 1;
		int onlineSize = 5;

		if (args.length > 0){
			try{
				k = Integer.parseInt(args[0]);
			}
			catch (NumberFormatException e) {
				System.err.println("1st Argument must be an integer");
		        System.exit(1);
			}
		}
			
		if (args.length > 1){
			try{
				n = Integer.parseInt(args[1]);
			}
			catch (NumberFormatException e) {
				System.err.println("2nd Argument must be an integer");
		        System.exit(1);
			}
		}
		
		if (args.length > 2){
			try{
				onlineSize = Integer.parseInt(args[2]);
			}
			catch (NumberFormatException e) {
				System.err.println("3rd Argument must be an integer");
		        System.exit(1);
			}
		}
	
		// TODO Auto-generated method stub
		String offlinePath = "data/MU.1.5meters.offline.trace", onlinePath = "data/MU.1.5meters.online.trace", resultPath = "fingerprintingKNN.txt";
		
		//Construct parsers
		File offlineFile = new File(offlinePath);
		Parser offlineParser = new Parser(offlineFile);
		System.out.println("Offline File: " +  offlineFile.getAbsoluteFile());
		
		File onlineFile = new File(onlinePath);
		Parser onlineParser = new Parser(onlineFile);
		System.out.println("Online File: " + onlineFile.getAbsoluteFile());
		
		//Construct trace generator
		TraceGenerator tg;
		try {
			tg = new TraceGenerator(offlineParser, onlineParser,offlineSize,onlineSize);
			
			//Generate traces from parsed files
			tg.generate();
			
			//Iterate the trace generated from the offline file
			List<TraceEntry> radiomap = tg.getOffline();	
			List<TraceEntry> onlineTraces = tg.getOnline();
			
			//create outputfile
			FileWriter fstream = new FileWriter(resultPath);
			BufferedWriter out = new BufferedWriter(fstream);
			out.write("#FingerprintingKNN Result File\n");
			
			for(int i = 0; i < n; i++){
				for(TraceEntry entry: onlineTraces) {
					//Print out coordinates for the collection point and the number of signal strength samples
					
					//true position:
					//System.out.println(entry.getGeoPosition().toStringWithoutOrientation());
					out.write(entry.getGeoPosition().toStringWithoutOrientation() + ";");
					
					//estimated position
					
					List<EntryDistance> resultEntries = new ArrayList<EntryDistance>();
					//Double resultDistance = Double.MAX_VALUE;
					//compare entry with all the entries in the radiomap.
					for(TraceEntry radiomapentry: radiomap) {
						//Filter access points from the the entry
						List<MACAddress> aps = radiomapentry.getSignalStrengthSamples().getSortedAccessPoints();
						Double res = 0.0;
						for(MACAddress mac: aps){
							if(entry.getSignalStrengthSamples().containsKey(mac)){
								List<Double> m1 = entry.getSignalStrengthSamples().getSignalStrengthValues(mac);
								List<Double> ss1 = radiomapentry.getSignalStrengthSamples().getSignalStrengthValues(mac);
								
								res = (ss1.get(0) - m1.get(0)) * (ss1.get(0) - m1.get(0)) + res;
							}
						}
						res = Math.sqrt(res);
						resultEntries.add(new EntryDistance(radiomapentry, res));
					}
					//sort the results in ascending order:
					Collections.sort(resultEntries, Collections.reverseOrder());
					GeoPosition avgPosition = GetKAvg(resultEntries, k);
					//System.out.println(avgPosition.toStringWithoutOrientation() + '\n');
					out.write(avgPosition.toStringWithoutOrientation() + '\n');		
				}
				System.out.println(i + "/" + n);
			}
			out.close();
			System.out.println("Done!");
			/*
			//Iterate the trace generated from the online file
			List<TraceEntry> onlineTrace = tg.getOnline();			
			for(TraceEntry entry: onlineTrace) {
				//Print out coordinates for the collection point and the number of signal strength samples
				System.out.println(entry.getGeoPosition().toString() + " - " + entry.getSignalStrengthSamples().size());
			}
			*/
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static GeoPosition GetKAvg(List<EntryDistance> resultEntries, int k) throws Exception {
		if(resultEntries.size() >= k){
			List<EntryDistance> workingList = resultEntries.subList(0, k);
			List<GeoPosition> geos = new ArrayList<GeoPosition>();
			for(EntryDistance theEntry:workingList){
				geos.add(theEntry.get_position());
			}
			return Statistics.avg(geos);
		}
		else
			throw new Exception("K is larger than the set to average...");
	}
}
